package com.fadis.cmd;

import com.fadis.data.FStringHash;
import com.fadis.FadisException;
import com.fadis.db.FadisDB;
import com.fadis.protocol.BulkString;
import com.fadis.protocol.LongNumber;
import com.fadis.protocol.RespArray;
import com.fadis.protocol.SimpleString;

import java.util.*;

public class CmdHash {

    // HSET hash field value
    // 新建返回1，覆盖返回0，类型错误error
    public static final class hset implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);
            String value = frame.getArg(3);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, true);
            int r = FStringHash.hset(map, field, value);
            return LongNumber.encodeInt(r);
        }
    }

    // HSETNX hash field value  ==> 不存在则设置，就是只新建
    //  新建返回1，因已存在而放弃操作返回0，类型错误error
    public static final class hsetnx implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);
            String value = frame.getArg(3);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, true);
            int r = FStringHash.hsetnx(map, field, value);
            return LongNumber.encodeInt(r);
        }
    }

    // HGET hash field
    // value或者null
    public static final class hget implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            String r = FStringHash.hget(map, field);
            return BulkString.encodedBulkString(r);
        }
    }

    // HEXISTS hash field
    // 存在1 不存在0
    public static final class hexists implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            Boolean r = FStringHash.hexists(map, field);
            return LongNumber.encodeInt(r ? 1 : 0);
        }
    }

    // HDEL key field [field …]
    // 返回成功移除的域的数量，key不存在返回0
    public static final class hdel implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String[] fields = new String[frame.getArgsCount() - 2];

            for (int i = 2; i < frame.getArgsCount(); i++) {
                fields[i-2] = frame.getArg(i);
            }

            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            int count = FStringHash.hdel(map, fields);
            return LongNumber.encodeInt(count);
        }
    }

    // HLEN key
    // 返回key中field的数量，key不存在返回0
    public static final class hlen implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            int r = FStringHash.hlen(map);
            return LongNumber.encodeInt(r);
        }
    }

    // HSTRLEN key field
    // field对应value的字符串长度，key不存在返回0
    public static final class hstrlen implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            int r = FStringHash.hstrlen(map, field);
            return LongNumber.encodeInt(r);
        }
    }

    // HINCRBY key field increment
    // 增加increment，key不存在或field不存在则置0再增加increment， key类型错误，field类型错误（ERR hash value is not an integer）
    public static final class hincrby implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);
            String incrementStr = frame.getArg(3);
            long increment = Long.parseLong(incrementStr);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, true);
            long r = FStringHash.hincrBy(map, field, increment);
            return LongNumber.encodeLong(r);
        }
    }

    // HINCRBYFLOAT key field increment
    // 增加increment，key不存在或field不存在则置0再增加increment， key类型错误，field类型错误（ERR hash value is not an float）

    public static final class hincrbyfloat implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String field = frame.getArg(2);
            String incrementStr = frame.getArg(3);
            Double increment = Double.parseDouble(incrementStr);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, true);
            Double r = FStringHash.hincrByFloat(map, field, increment);
            return SimpleString.encodedSimpleString(r+"");
        }
    }

    // HMSET key field value [field value …]
    // 返回OK
    public static final class hmset implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            if(frame.getArgsCount() <= 4){
                throw new FadisException(4001, "ERR wrong number of arguments for 'hmset' command");
            }
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, true);

            Map<String, String> map2 = new HashMap<>();

            String t_key = null;
            for (int i = 2; i < frame.getArgsCount(); i++) {
                if(t_key == null) {
                    t_key = frame.getArg(i);
                } else{
                    map2.put(t_key, frame.getArg(i));
                    t_key = null;
                }
            }

            String r = FStringHash.hmset(map, map2);
            return SimpleString.encodedSimpleString("OK");
        }
    }

    // HMGET key field [field …]
    // 返回list，即对应fields的values，顺序和fileds一致
    public static final class hmget implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);

            String[] keys = new String[frame.getArgsCount() - 2];
            for (int i = 1; i < frame.getArgsCount(); i++) {
                keys[i - 2] = (frame.getArg(i));
            }

            List<String> values = FStringHash.hmget(map, key);

            return RespArray.encodeList(values);
        }
    }

    // HKEYS key
    // 返回keys，或者空表（非null），key不存在也是空表
    public static final class hkeys implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            Set<String> r = FStringHash.hkeys(map);
            return RespArray.encodeSet(r);
        }
    }

    // HVALS key
    // 返回values，或者空表（非null），key不存在也是空表
    public static final class hvals implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            List<String> r = FStringHash.hvals(map);
            return RespArray.encodeList(r);
        }
    }

    // HGETALL key
    // 以列表形式返回哈希表的域和域的值  [field1, value1, field2, value2 ...]，key不存在也是空表
    public static final class hgetall implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            HashMap<String, String> map = FadisDB.tryToGetOrCreateHash( key, false);
            Map<String, String> r = FStringHash.hgetAll(map);

            List<String> list = new ArrayList<>();
            for (String k: r.keySet()){
                list.add(k);
                list.add(r.get(k));
            }

            return RespArray.encodeList(list);
        }
    }

//    public static final class hscan  implements CmdHandler{
//        @Override
//        public String run(RedisFrame frame) throws FakeDataException {
//            return null;
//        }
//    }
}
